# 一.面向对象编程

## 1.基础定义
```
类：类是对象的类型模板，例如，定义Student类来表示学生，类本身是一种类型，Student表示学生类型，但不表示任何具体的某个学生；

实例：实例是根据类创建的对象，例如，根据Student类可以创建出xiaoming、xiaohong、xiaojun等多个实例，每个实例表示一个具体的学生，他们全都属于Student类型。
```

## 2.JavaScript不区分类和实例的概念，而是通过原型（prototype）来实现面向对象编程。
```
原型是指当我们想要创建xiaoming这个具体的学生时，我们并没有一个Student类型可用。那怎么办？恰好有这么一个现成的对象：

var robot = {
    name: 'Robot',
    height: 1.6,
    : function () {
        console.log(this.name + ' is ning...');
    }
};
```
```
我们看这个robot对象有名字，有身高，还会跑，有点像小明，干脆就根据它来“创建”小明得了！

于是我们把它改名为Student，然后创建出xiaoming：

var Student = {
    name: 'Robot',
    height: 1.2,
    : function () {
        console.log(this.name + ' is ning...');
    }
};

var xiaoming = {
    name: '小明'
};

xiaoming.__proto__ = Student;
```
```
注意最后一行代码把xiaoming的原型指向了对象Student，看上去xiaoming仿佛是从Student继承下来的：

xiaoming.name; // '小明'
xiaoming.(); // 小明 is ning...


xiaoming有自己的name属性，但并没有定义()方法。不过，由于小明是从Student继承而来，只要Student有()方法，xiaoming也可以调用
```

## 3.如果你把xiaoming的原型指向其他对象
```
var Bird = {
    fly: function () {
        console.log(this.name + ' is flying...');
    }
};


xiaoming.__proto__ = Bird;
现在xiaoming已经无法()了，他已经变成了一只鸟：


xiaoming.fly(); // 小明 is flying...
在JavaScrip代码运行时期，你可以把xiaoming从Student变成Bird，或者变成任何对象。
```
```
请注意，上述代码仅用于演示目的。在编写JavaScript代码时，不要直接用obj.proto__去改变一个对象的原型，并且，低版本的IE也无法使用__proto。Object.create()方法可以传入一个原型对象，并创建一个基于该原型的新对象，但是新对象什么属性都没有，因此，我们可以编写一个函数来创建xiaoming：

// 原型对象:
var Student = {
    name: 'Robot',
    height: 1.2,
    : function () {
        console.log(this.name + ' is ning...');
    }
};

function createStudent(name) {
    // 基于Student原型创建一个新对象:
    var s = Object.create(Student);
    // 初始化新对象:
    s.name = name;
    return s;
}

var xiaoming = createStudent('小明');
xiaoming.(); // 小明 is ning...
xiaoming.__proto__ === Student; // true
```

# 3.class继承

```
我们先回顾用函数实现Student的方法：

function Student(name) {
    this.name = name;
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

```
```
如果用新的class关键字来编写Student，可以这样写：

class Student {
    constructor(name) {
        this.name = name;
    }

    hello() {
        alert('Hello, ' + this.name + '!');
    }
}

比较一下就可以发现，class的定义包含了构造函数constructor和定义在原型对象上的函数hello()（注意没有function关键字），这样就避免了Student.prototype.hello = function () {...}这样分散的代码。
```
```
最后，创建一个Student对象代码和前面章节完全一样：

var xiaoming = new Student('小明');
xiaoming.hello();
```
```
class继承
用class定义对象的另一个巨大的好处是继承更方便了。想一想我们从Student派生一个PrimaryStudent需要编写的代码量。现在，原型继承的中间对象，原型对象的构造函数等等都不需要考虑了，直接通过extends来实现：

class PrimaryStudent extends Student {
    constructor(name, grade) {
        super(name); // 记得用super调用父类的构造方法!
        this.grade = grade;
    }

    myGrade() {
        alert('I am at grade ' + this.grade);
    }
}
注意PrimaryStudent的定义也是class关键字实现的，而extends则表示原型链对象来自Student。子类的构造函数可能会与父类不太相同，例如，PrimaryStudent需要name和grade两个参数，并且需要通过super(name)来调用父类的构造函数，否则父类的name属性无法正常初始化。
```